﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Threading;
using System.Drawing;
using System.ServiceModel.Channels;
using System.Drawing.Imaging;
using System.IO;
using System.Net;

namespace PresentItNow
{
    [ServiceBehavior( InstanceContextMode = InstanceContextMode.Single)]
    class Host : IContract
    {
        public Host()
        {

        }

        private ImageCodecInfo jgpEncoder = Utils.GetEncoder(ImageFormat.Jpeg);        

        public void StartHosting()
        {
            Thread t = new Thread(new ThreadStart(hostMe));
            t.IsBackground = true;
            t.Start();            
        }

        public void StopHosting()
        {
            host.Close();            
        }

        private void hostMe()
        {   
            host = new ServiceHost(this);            

            Binding binding = Utils.CreateBinding();
            

            string hostName = Dns.GetHostName();
            string address = string.Format("net.tcp://{0}:31415/ScreenShare", hostName);

            host.AddServiceEndpoint(typeof(IContract), binding, address);
            
            

            try
            {
                host.Open();
                if (HostingStartedSuccessfully != null)
                    HostingStartedSuccessfully();
            }
            catch (Exception ex)
            {
                if (UnableToHost != null)
                UnableToHost(ex);                
            }
        }

        ServiceHost host = null;

        public event Action HostingStartedSuccessfully;
        public event Action<Exception> UnableToHost;


        

        private Bitmap lastPictureBuffer;

        private object syncRoot = new object();

        public Bitmap LastPictureBuffer
        {
            get
            {
                lock (syncRoot)
                {
                    return lastPictureBuffer;
                }
            }
            set
            {
                lock (syncRoot)
                {
                    lastPictureBuffer = value;
                }
            }
        }

        public byte[] GetPicture(ClientInfo clientInfo, double quality)
        {
            StoreClientInfo(clientInfo);

            Bitmap lastPicture = LastPictureBuffer;

            //Convert
            MemoryStream stream = new MemoryStream();

            if (quality == 100)
            {
                lastPicture.Save(stream, ImageFormat.Png);
            }
            else
            {
                //ImageCodecInfo jgpEncoder = Utils.GetEncoder(ImageFormat.Jpeg);
                //log.AppendLine("GetEncoder took: " + DateTime.Now.Subtract(started).TotalMilliseconds);
                //started = DateTime.Now;

                // Create an Encoder object based on the GUID
                // for the Quality parameter category.
                //System.Drawing.Imaging.Encoder myEncoder =
                //    System.Drawing.Imaging.Encoder.Quality;
                

                // Create an EncoderParameters object.
                // An EncoderParameters object has an array of EncoderParameter
                // objects. In this case, there is only one
                // EncoderParameter object in the array.

                EncoderParameters myEncoderParameters = new EncoderParameters(1);
                long jpegQuality = (long)(quality / 100.0 * 80.0); //Max jpeg quality is 80, else we use png

                EncoderParameter myEncoderParameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, jpegQuality);                

                myEncoderParameters.Param[0] = myEncoderParameter;
                lastPicture.Save(stream, jgpEncoder, myEncoderParameters);

                //log.AppendLine("bmp.Save took: " + DateTime.Now.Subtract(started).TotalMilliseconds);
                //started = DateTime.Now;
            }


            byte[] bytes = stream.GetBuffer();
            //log.AppendLine("stream.GetBuffer took: " + DateTime.Now.Subtract(started).TotalMilliseconds);
            //started = DateTime.Now;

            
            return bytes;
        }

        private object clientInfoSync = new object();

        Dictionary<string, ClientInfo> clientInfos = new Dictionary<string, ClientInfo>();

        private void StoreClientInfo(ClientInfo clientInfo)
        {
            if (!string.IsNullOrEmpty(clientInfo.Name))
            {
                lock (clientInfoSync)
                {
                    clientInfos[clientInfo.Name] = clientInfo;
                }
            }
        }

        public List<ClientInfo> GetClientInfos()
        {
            lock (clientInfoSync)
            {
                List<ClientInfo> infos = new List<ClientInfo>(clientInfos.Values);
                return infos;
            }
        }

        public void Ping()
        {
            return;
        }
    }
}
